package com.taobao.client.component.templete;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;

/**
 * the html template's base class.
 * @author crane.ding
 * @version 1.0 2008-11-21
 */
public class HTMLTemplateBase extends HTMLPanel {

	protected static String loadingHTML = "<div align='center' style='margin:auto;'>"
			+ "<div style='color:#003399;font-weight:bold;'>正在加载中...</div>"
			+ "<div></div>" + "</div>";

	/**
	 * the all user's widgets.
	 */
	protected Map<String, Widget> widgets = new HashMap<String, Widget>();
	/**
	 * the all parses widgets.
	 */
	protected Map<String, Widget> pageWidget = new HashMap<String, Widget>();
	/**
	 * this is element in the page.
	 */
	protected Map<String, Element> htmlElements = new HashMap<String, Element>();

	public class HTMLTemplateBaseException extends RuntimeException {
		private static final long serialVersionUID = 4259780677125186344L;

		public HTMLTemplateBaseException(String error) {
			super(error);
		}
	}

	public HTMLTemplateBase() {
		super(loadingHTML);
	}

	public HTMLTemplateBase(String html) {
		super(html);
	}

	protected void setTemplateContent() {
		findPageWidgets(getElement());
		beforeFlushChildren();
		flushChildren(getElement());
		afterTemplateLoaded();
	}

	/**
	 * find all the element,which have a gwtid attribte.
	 * 
	 * @param el element in the page
	 */
	protected void findPageWidgets(Element el) {
		String gwtid = getElementAttribute(el, "gwtid");
		if (gwtid != null) {
			htmlElements.put(gwtid, el);

			Widget widget = AutoRebindWidget.rebindWidget(el);
			pageWidget.put(gwtid, widget);
			if (widgets.get(gwtid) == null)
				widgets.put(gwtid, widget);
		} else {
			int count = DOM.getChildCount(el);
			for (int i = 0; i < count; i++) {
				findPageWidgets(DOM.getChild(el, i));
			}
		}
	}

	/**
	 * before parses the page element.<br>
	 * you can set widget in this method.
	 */
	protected void beforeFlushChildren() {
	}

	/**
	 * parses all element into page.
	 */
	protected void flushChildren(Element els) {
		Set<String> keySet = htmlElements.keySet();
		for (String gwtid : keySet) {
			Element el = (Element) htmlElements.get(gwtid);
			Widget widget = getNamedWidget(gwtid);
			if (widget == null) {
				Element promptDiv = DOM.createSpan();
				DOM.setInnerHTML(promptDiv, "!not defined!");
				replaceChild(DOM.getParent(el), promptDiv, el);
				continue;
			}
			Element container = DOM.createSpan();
			Element parent = DOM.getParent(el);
			replaceChild(parent, container, el);
			// 这样处理是保证自建的Element具有事件处理的能力
			super.add(widget, container);
			// 删除多于的span 保持原有的Element
			replaceChild(parent, widget.getElement(), container);
		}
	}

	/**
	 * get the widget by gwtid.
	 */
	public Widget getGwtWidget(String gwtid) {
		return pageWidget.get(gwtid) != null ? pageWidget.get(gwtid) : widgets
				.get(gwtid);
	}

	public void putWidget(String gwtid, Widget widget) {
		if (widget == null)
			widget = new HTML("The widgets is not allowed null to gwtid = ("
					+ gwtid + ")");
		widgets.put(gwtid, widget);
	}

	protected Widget getNamedWidget(String gwtid) {
		Object widg = widgets.get(gwtid);
		if (widg instanceof Widget)
			return (Widget) widgets.get(gwtid);
		else
			return new HTML("!not defined!");
	}

	private static native String getElementAttribute(Element element,
			String attr) /*-{
		return element.getAttribute(attr);
	}-*/;

	public static native void replaceChild(Element parent, Element newChild,
			Element oldChild) /*-{
		parent.replaceChild(newChild, oldChild);
	}-*/;

	/**
	 * after all widgets into the page.<br>
	 * you can do anything with widget in this method.
	 */
	protected void afterTemplateLoaded() {

	}

	public HTML getGwtHTML(String gwtid) {
		isNULLWidget(gwtid);
		if (!(getGwtWidget(gwtid) instanceof HTML)) {
			throwHTMLTemplateBaseException("This object (gwtid=" + gwtid
					+ ") is not HTML.");
		}
		return (HTML) getGwtWidget(gwtid);
	}

	public Image getGwtImage(String gwtid) {
		isNULLWidget(gwtid);
		if (!(getGwtWidget(gwtid) instanceof Image)) {
			throwHTMLTemplateBaseException("This object (gwtid=" + gwtid
					+ ") is not Image.");
		}
		return (Image) getGwtWidget(gwtid);
	}

	public ListBox getGwtListBox(String gwtid) {
		isNULLWidget(gwtid);
		if (!(getGwtWidget(gwtid) instanceof ListBox)) {
			throwHTMLTemplateBaseException("This object (gwtid=" + gwtid
					+ ") is not ListBox.");
		}
		return (ListBox) getGwtWidget(gwtid);
	}

	public CheckBox getGwtCheckBox(String gwtid) {
		isNULLWidget(gwtid);
		if (!(getGwtWidget(gwtid) instanceof CheckBox)) {
			throwHTMLTemplateBaseException("This object (gwtid=" + gwtid
					+ ") is not CheckBox.");
		}
		return (CheckBox) getGwtWidget(gwtid);
	}

	public PasswordTextBox getGwtPasswordTextBox(String gwtid) {
		isNULLWidget(gwtid);
		if (!(getGwtWidget(gwtid) instanceof PasswordTextBox)) {
			throwHTMLTemplateBaseException("This object (gwtid=" + gwtid
					+ ") is not PasswordTextBox.");
		}
		return (PasswordTextBox) getGwtWidget(gwtid);
	}

	public Button getGwtButton(String gwtid) {
		isNULLWidget(gwtid);
		if (!(getGwtWidget(gwtid) instanceof Button)) {
			throwHTMLTemplateBaseException("This object (gwtid=" + gwtid
					+ ") is not Button.");
		}
		return (Button) getGwtWidget(gwtid);
	}

	public TextBox getGwtTextBox(String gwtid) {
		isNULLWidget(gwtid);
		if (!(getGwtWidget(gwtid) instanceof TextBox)) {
			throwHTMLTemplateBaseException("This object (gwtid=" + gwtid
					+ ") is not TextBox.");
		}
		return (TextBox) getGwtWidget(gwtid);
	}

	public TextArea getGwtTextArea(String gwtid) {
		isNULLWidget(gwtid);
		if (!(getGwtWidget(gwtid) instanceof TextArea)) {
			throwHTMLTemplateBaseException("This object (gwtid=" + gwtid
					+ ") is not TextArea.");
		}
		return (TextArea) getGwtWidget(gwtid);
	}

	public RadioButton getGwtRadioButton(String gwtid) {
		isNULLWidget(gwtid);
		if (!(getGwtWidget(gwtid) instanceof RadioButton)) {
			throwHTMLTemplateBaseException("This object (gwtid=" + gwtid
					+ ") is not RadioButton.");
		}
		return (RadioButton) getGwtWidget(gwtid);
	}

	private void isNULLWidget(String gwtid) {
		if (getGwtWidget(gwtid) == null) {
			throwHTMLTemplateBaseException("This gwtid='" + gwtid
					+ "' is not defined.");
		}
	}

	private void throwHTMLTemplateBaseException(String error)
			throws HTMLTemplateBaseException {
		throw new HTMLTemplateBaseException(error);
	}
}
